namespace Xmef.Engine.Internal
{
    using System;
    using System.Collections.Generic;
    using Xmef.Engine;
    using Xmef.Interfaces;
    using Xmef.Library;

    [Serializable]
    internal class PluginConfiguration<T> : PluginConfiguration, IPluginConfiguration, IPluginCollectionContainer, IPluginIdentity, IPluginEnumerator
    {
        private readonly IPluginHost _host;
        private bool _loaded;

        public PluginConfiguration()
        {
        }

        public PluginConfiguration(string hostName, string fileName, bool isDefault) : base(hostName, fileName, isDefault)
        {
            this._host = ConfigurationManager.Create(hostName, fileName, isDefault);
        }

        public IEnumerable<IPluginObject> GetActivePlugins(Predicate<IPluginObject> match)
        {
            return this.PluginHost.GetActivePlugins(match);
        }

        public IEnumerable<IPluginObject> GetLoadedPlugins(Predicate<IPluginObject> match)
        {
            return this.PluginHost.GetLoadedPlugins(match);
        }

        private bool Load()
        {
            if (!this._loaded)
            {
                try
                {
                    ConfigurationManager.Load<T>(this._host);
                    this._loaded = true;
                    return true;
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorSync(ex);
                    return false;
                }
            }
            return true;
        }

        public bool Load(string fileName)
        {
            try
            {
                IXmlPluginConfigurationInternal host = this;
                if (PluginConfigurationManager.XmlFileSerializer.Attach(fileName))
                {
                    if (PluginConfigurationManager.XmlFileSerializer.Deserialize(PluginConfigurationManager.Formatter))
                    {
                        PluginConfigurationManager.XmlFileSerializer.Detach(fileName);
                        IPluginConfigurationManagerInternal configuration = host.InternalConfigurationManager;
                        if (configuration != null)
                        {
                            configuration.Assign(PluginConfigurationManager.XmlFileSerializer.RuntimeObject);
                        }
                        return true;
                    }
                    PluginConfigurationManager.XmlFileSerializer.Detach(fileName);
                }
                return false;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorSync(ex);
                return false;
            }
        }

        public bool LoadConfiguration(IPluginHostManager manager, string hostName)
        {
            if ((!this._loaded && this.LoadConfigurationFile(FileName)) && this.Load())
            {
                manager.AddHost(hostName, this);
                return true;
            }
            return false;
        }

        private bool LoadConfigurationFile(string fileName)
        {
            if (!this.Load(fileName))
            {
                return false;
            }
            return true;
        }

        public bool Save(string fileName)
        {
            try
            {
                IXmlPluginConfigurationInternal host = this;
                if (PluginConfigurationManager.XmlFileSerializer.Attach(fileName))
                {
                    if (PluginConfigurationManager.XmlFileSerializer.Serialize(host.InternalConfigurationManager, PluginConfigurationManager.Formatter))
                    {
                        PluginConfigurationManager.XmlFileSerializer.Detach(fileName);
                        return true;
                    }
                    PluginConfigurationManager.XmlFileSerializer.Detach(fileName);
                }
                return false;
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorSync(ex);
                return false;
            }
        }

        private bool SaveConfigurationFile(string fileName)
        {
            if (!this.Save(fileName))
            {
                return false;
            }
            return true;
        }

        private bool Unload()
        {
            if (this._loaded)
            {
                try
                {
                    ConfigurationManager.Unload<T>(this._host);
                    this._loaded = false;
                    return true;
                }
                catch (Exception ex)
                {
                    LogHelper.WriteErrorSync(ex);
                    return false;
                }
            }
            return true;
        }

        public bool UnloadConfiguration(IPluginHostManager manager, string hostName)
        {
            if ((this._loaded && this.SaveConfigurationFile(FileName)) && this.Unload())
            {
                manager.RemoveHost(hostName, this);
                return true;
            }
            return false;
        }

        public IEnumerable<IPluginObject> ActivePlugins
        {
            get
            {
                return this._host.ActivePlugins;
            }
        }

        public int Count
        {
            get
            {
                return this._host.Count;
            }
        }

        public bool IsLoaded
        {
            get
            {
                return this._loaded;
            }
        }

        public IEnumerable<IPluginObject> LoadedPlugins
        {
            get
            {
                return this._host.LoadedPlugins;
            }
        }

        public IPluginHost PluginHost
        {
            get
            {
                return this._host;
            }
        }
    }
}

